// @author Tim Major
// @customized Ben Loveridge
// @revision 20071015-1111
//   -added support for publish webfeeds without changing player behavior

//Fix for vslider bug
MN.Widget.VSlider.prototype.Value = function(y, fireEvent)
{   // gets/sets the value of the slider and moves the thumb accordingly
	if (y == null)
		return this.curValue;

	y = this.minValue + this.ClipValue(y);
	var oldValue = this.curValue;
	this.curValue = y;
	this.thumb.style.top = this.CalcThumbPosition(y) + 'px';

	if (fireEvent)
		this.FireEvent('ValueChanged', this.curValue);
};

MN.Playlist = MN.Class(MN.EventSource);
_pp = MN.Playlist.prototype;

_pp.initialize = function(qmp, divID, dropdownID, scrollID){
	MN.EventSource.prototype.initialize.apply(this);
	this.qmp = qmp;
	this._epg;
	this._curURL = '';
	this._curShow = 0;
	this._viewer = $(divID);
	if(scrollID && $(scrollID)){
		this._scroller = new MN.Widget.VSlider($(scrollID), 0, 100);
		MN.Event.Observe(this._scroller, 'ValueChanged', this._ScrollChanged);
	}
	//these are used for pagination
	this._curPage = 0;
	this._numOfPages = 0;
	//arrays for dropdown
	this._dayArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
	this._monthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

	if(dropdownID && $(dropdownID)){
		this._dropdown = $(dropdownID);
		MN.Event.Observe(this._dropdown, 'change', this._SelectContent);
	}

	//grab the show box template
	var showBoxTemplate = MN.Widget.FindNonTextChild($(divID));
	if(showBoxTemplate){
		this._boxTemplate = $(divID).removeChild(showBoxTemplate);
		this._boxTemplate.style.display = 'block';
		this._boxTemplate.style.visibility = 'visible';
	}
	else{
		this._boxTemplate = document.createElement('table');
		var newRow = this._boxTemplate.insertRow(-1);
		var newCell = newRow.insertCell(-1);
		newCell.className = 'mn_show_thumb';
		newCell = newRow.insertCell(-1);
		newCell.className = 'mn_show_startTime';
		newCell = newRow.insertCell(-1);
		newCell.className = 'mn_show_title';
	}

	//create the scroll pane widget
	this._canvas = document.createElement('div');
	this._viewer.appendChild(this._canvas);
	this._scrollPane = new MN.Widget.ScrollPane(divID);
	//W3C browsers add a bit of "padding" to the offsetTop number
	//when there is a border around the playlist.  The offsetTop
	//number needs to be set to 0 initially, and the offset "offset" needs
	//to be used everytime thereafter
	this._offset = -this._canvas.offsetTop;

	MN.Event.Observe(this.qmp, 'TimelineLoaded', this._OnTimelineLoaded);
	MN.Event.Observe(this.qmp, 'ShowChanged', this._OnShowChanged);
}

_pp._OnTimelineLoaded = function(qvt){
	//the player has either loaded a new url, or the open-ended timeline
	//has reloaded and we need to refresh the playlist

	if((qvt.GetSource() != this._curURL) || qvt.IsOpenEnded())
		this._LoadQVT(qvt, qvt.IsOpenEnded());
	else
		log('playlist: timeline already loaded in playlist');
}

_pp._LoadQVT = function(qvt, reload){
	MN.Event.StopObserving(qvt, 'TimelineLoaded', this._LoadQVT);

	// give gap clips descriptive metadata
	for(var i = 0; i < qvt.meta.shows.length; i++){
		var show = qvt.meta.shows[i];
		if(!show.title && !show.desc && !show.description){
			show.isGap = show.off = true;
		}
	}

	if(!reload)
		this._curShow = 0;
	this._Populate(qvt);
}

_pp._OnShowChanged = function(showNum, title){
	var qvt = this.qmp.CurrentQVT();
	if(showNum < 0 || showNum >= qvt.ShowCount())
		showNum = qvt.ShowCount() - 1;

	//do the highlights
	/*if(this._SameURLAsPlayer()){
		var showBoxes = this._canvas.childNodes;
		for(var i = 0; i < showBoxes.length; i++){
			if(showBoxes[i].getAttribute("playing") == "true"){
				log('remove highlight: ',i)
				showBoxes[i].className = showBoxes[i].className.replace('mn_highlight', '');
				showBoxes[i].setAttribute("playing","false");
			}
		}
		//if(showBoxes[this._curShow])
			//showBoxes[this._curShow].className = showBoxes[this._curShow].className.replace('mn_highlight', '');
		//showBoxes[showNum].className += ' mn_highlight';
		for(var i = 0; i < showBoxes.length; i++){
			if(showNum == showBoxes[i].getAttribute("shownumber")){
				log('highlight: ',i)
				showBoxes[i].className += ' mn_highlight';
				showBoxes[i].setAttribute("playing","true");
				this._ScrollIntoView(i);
			}
		}
	}
	*/
	if(this._SameURLAsPlayer()){
		this._ScrollIntoView(showNum);
	}

	this._curShow = showNum;
}

_pp._SameURLAsPlayer = function(){
	//return this.qmp.CurrentQVT().PrimaryURL() == this._curURL;
	return this.qmp.CurrentQVT().GetSource() == this._curURL;
}

_pp._Populate = function(qvt){
	//this._curURL = qvt.PrimaryURL();
	this._curURL = qvt.GetSource();

	//clear out the old playlist
	while(this._canvas.childNodes.length > 0){
		this._canvas.removeChild(this._canvas.childNodes[0]);
	}
	//make sure the right dropdown item is selected
	if(this._dropdown){
		for(var i = 0; i < this._dropdown.options.length; i++){
			if(this._dropdown[i].value == this._curURL){
				this._dropdown[i].selected = true;
				break;
			}
		}
	}

 	qvt.meta.mn_content_type = 'live';
	var contentType = qvt.Metadata('mn_content_type') || MN.TP.curChnl.contentType || 'vod';
	if(qvt.PrimaryURL().search('byid') != -1)
		contentType = 'vod';
	var curShow;
	var highlight;
	var isLastShow;
	var clipCount = 0;
		logError('POPULATING - NO. OF SHOWS: ', qvt.shows.length)
	if(qvt.HaveAnyLive() && qvt.IsOpenEnded()) //live, but not from Publish (sometimes HaveAnyLive() returns true for previous days, but IsOpenEnded() doesnt)
		var length = qvt.shows.length - 1; //we don't want to display the currently-live show in the playlist, so drop the length by 1
	else if(qvt.IsAnchored()) { //timeline is anchored, ie Publish
		var length = qvt.TimelineToShow(qvt.GetTimelineNow()); //don't show currently live show
		length = (length > qvt.shows.length) ? qvt.shows.length : length; //don't try to create boxes for non-shows (yesterday's QVT TimelineToNow returns an extra show)
	}
	else
		var length = qvt.shows.length;

	for(var i = 0; i < length; i++){
		curShow = qvt.shows[i];
		curShow.isGap = (!curShow.title && !curShow.desc && !curShow.description);
		if(!curShow.off && !curShow.isGap && (curShow.geoAllowed == null || curShow.geoAllowed)){ //only display shows without "off" metadata and that haven't been geofiltered out
			clipCount += 1;
			curShow.thumbnail = curShow.thumbnail;
			curShow.title = curShow.title || 'No Title';
			/** REMOVED 9/5/07 -- doesn't work after changing the play style from CurrentPosition(start) to Play(qvt,start,stop) in playlist.js;
	 		 *	FIND A FIX
	 		 */
			//highlight = (this._SameURLAsPlayer() && i == this._curShow && !MN.TP.onLive); //onLive is null when the first list populates, so this avoids highlighting the wrong item initially
			//highlight = (this._SameURLAsPlayer() && i == MN.TP.curShow && !MN.TP.onLive);
			highlight = (this._SameURLAsPlayer() && (i == MN.TP.curShow && curShow.tlStartTime + .1 == MN.TP.startPos || curShow.tlStartTime == 0 && MN.TP.startPos != 0 && MN.TP.stopPos == -1) && !MN.TP.onLive);
			isLastShow = (!qvt.HaveAnyLive() && !qvt.IsAnchored() && i == length - 1);

			//TODO: timezoneOverride
			var box;
			if(contentType == 'live')
				box = this._CreateShowBox(curShow, qvt.PosToDatetime, highlight, isLastShow);
			else if(contentType == 'vod')
				box = this._CreateShowBox(curShow, null, highlight, isLastShow);

			box.className += clipCount % 2 == 0 ? ' mn_clip1' : ' mn_clip2';
			box.setAttribute("id", "clip" + clipCount); //this is so CustomPlLoaded can set up Observes for each to set start/stop time
			box.setAttribute("shownumber",i);
			this._canvas.appendChild(box);
		}else{
			log('metadata "off":', i);//length--;
		}
	}

	this._UpdatePages();

	//get the text to pass with the event
	if(contentType == 'live'){
			var date = qvt.StartDatetime();
			text = date.month + "/" + date.day + "/" + date.year; //month is 1 based
	}
	else if(contentType == 'vod')
		text = qvt.Metadata('title') || 'No Title';

	if(this._SameURLAsPlayer()){
		this._ScrollIntoView(this._curShow);
	}

	this.FireEvent('Populated', this._curURL, text);
}

_pp._CreateShowBox = function(show, posToDatetime, highlight, isLastShow){
	var newBox = MN.PopulateTemplate(this._boxTemplate, show, posToDatetime);
	newBox.style.cursor = 'pointer';
	if(highlight){
		newBox.className += ' mn_highlight';
		newBox.setAttribute("playing","true");
	}

	var func = MN.MakeBound(this, this._ShowClicked);
	MN.Event.Observe(newBox, 'click', function(){func(show.tlStartTime, show.tlStopTime, isLastShow)}); //added stopTime so I can play only that show; isLastShow so I can handle it specially
	//IE doesn't support :hover for anything but anchors, so add mouseovers
	MN.Event.Observe(newBox, 'mouseover', function(){newBox.className += ' mn_highlight';});
	MN.Event.Observe(newBox, 'mouseout', function(){newBox.className = newBox.className.replace('mn_highlight', '');});
	return newBox;
}
var custClip;
var custQVT;
_pp._ShowClicked = function(start,stop,isLastShow){
	/*if(!this._SameURLAsPlayer()){
		log('Playlist: changing qvt');
		this.qmp.Play(this._curURL, start);
	}
	else{
		log('same qvt: playing');
		this.qmp.CurrentPosition(start);
	}*/

	//try and prevent watching past show end in the first place
	var scrubbing = false;
	start += .1;
	stop = (isLastShow) ? -1 : stop - .1;
	if(MN.TP.qmp.scrubbing || MN.TP.scrubRate != 0) { //don't change the show while scrubbing; pause it instead
		scrubbing = true;
	}

	//alert('CurURL: ' + this._curURL + '\nPrimaryURL: ' + this.qmp.CurrentQVT().PrimaryURL() + '\nSameAsPlayer? ' + this._SameURLAsPlayer());
	if(!this._SameURLAsPlayer()){
		log('Playlist: changing qvt');
		if(scrubbing){
			MN.TP.Play();
			if(isLastShow)
				this.qmp.Play(this._curURL, start);
			else
				this.qmp.Play(this._curURL, start, stop);
			setTimeout('MN.TP.Play()',1000);
		}
		else {
			this.qmp.Play(this._curURL, start, stop);
		}
	}
	else{
		log('same qvt: playing');
		//this.qmp.CurrentPosition(start);
		if(scrubbing){
			MN.TP.Play();
			if(isLastShow)
				this.qmp.Play(this.qmp.CurrentQVT().GetSource(),start);
			else
				this.qmp.Play(this.qmp.CurrentQVT().GetSource(),start,stop);
			setTimeout('MN.TP.Play()',1000);
		}
		else {
			this.qmp.Play(this.qmp.CurrentQVT().GetSource(),start,stop);
		}
	}
	//set global start/stop/other variables to do extra checks to keep within show bounds
	MN.TP.startPos = start;
	MN.TP.stopPos = stop;
	MN.TP.onLive = false;
	MN.TP.showChangedOnClick = true;
}

_pp._ScrollIntoView = function(showNum){
	//check if the element needs to scroll into view
	// var elem = this._canvas.childNodes[showNum];
	var elem;
	var showDivs = this._canvas.childNodes;
	for(var i = 0; i < showDivs.length; i++){
		if(showDivs[i].getAttribute("shownumber") == showNum){
			elem = showDivs[i];
			break;
		}
	}
	if(elem.offsetHeight > 0){
		var elemBottom = elem.offsetTop + elem.offsetHeight;
		var relBottom = elemBottom + (this._canvas.offsetTop + this._offset); //offsetTop is a negative number
		var relTop = elem.offsetTop + (this._canvas.offsetTop + this._offset);

		if(relBottom > this._viewer.offsetHeight){
			this.PageDown();
			this._ScrollIntoView(showNum);
		}
		else if(relTop < 0){
			this.PageUp();
			this._ScrollIntoView(showNum);
		}
	}
}


_pp._UpdatePages = function(){
	var numBoxesAllowed = Math.floor(this._viewer.offsetHeight / this._canvas.firstChild.offsetHeight);
	var pageBump = this._canvas.firstChild.offsetHeight * numBoxesAllowed;
	//clear old playlist
	//this._numOfPages = Math.ceil(this._canvas.offsetHeight / this._viewer.offsetHeight);
	this._numOfPages = Math.ceil(this._canvas.childNodes.length / numBoxesAllowed);
	this._curPage = 0;
	this._canvas.style.top = '0px';
	this._pagePositions = [];
	for(var i = 0; i < this._numOfPages; i++){
		this._pagePositions.push(pageBump * i);
	}

	if(this._scroller && this._numOfPages > 1){
			$('mn_pl_scroller').style.visibility = 'visible';
			$('mn_pl_scroll_up').style.visibility = 'visible';
			$('mn_pl_scroll_down').style.visibility = 'visible';
			this._scroller.thumb.style.visibility = 'visible';
	  this._scroller.Value(0);
	  this._scroller.SetRange(0, this._canvas.offsetHeight - pageBump);
	}
	else if(this._scroller){
		this._scroller.thumb.style.visibility = 'hidden';
		$('mn_pl_scroller').style.visibility = 'hidden';
		$('mn_pl_scroll_up').style.visibility = 'hidden';
		$('mn_pl_scroll_down').style.visibility = 'hidden';
	}

	this.FireEvent('PageChanged', this._curPage + 1, this._numOfPages);
}

_pp.PageUp = function(){
	if(this._curPage >= 1){
		//this._canvas.style.top = -this._pagePositions[--this._curPage] + 'px';
		this._scrollPane.Position(0, this._pagePositions[--this._curPage]);
		if(this._scroller){
			this._scroller.Value(this._pagePositions[this._curPage]);
		}
		this.FireEvent('PageChanged', this._curPage + 1, this._numOfPages);
	}
}

_pp.PageDown = function(){
	if(this._curPage < this._numOfPages - 1){
		//this._canvas.style.top = -this._pagePositions[++this._curPage] + 'px';
		this._scrollPane.Position(0, this._pagePositions[++this._curPage]);
		if(this._scroller){
			this._scroller.Value(this._pagePositions[this._curPage]);
		}
		this.FireEvent('PageChanged', this._curPage + 1, this._numOfPages);
	}
}

_pp.ScrollUp = function(){
	//don't do anything if plScrolling variable doesn't exist or is false
	if(typeof plScrolling == 'undefined' || plScrolling == false)
		return;

	if(this._scroller){
		var scrollVal = this._scroller.Value();
		scrollVal = (scrollVal > this._scroller.minValue + 8) ? scrollVal -= 8 : this._scroller.minValue;

		this._scroller.Value(scrollVal);
		this._ScrollChanged(scrollVal);
		setTimeout('MN.TP.qmp.playlist.ScrollUp()',50);
	}
}

_pp.ScrollDown = function(){
	//don't do anything if plScrolling variable doesn't exist or is false
	if(typeof plScrolling == 'undefined' || plScrolling == false)
		return;

	if(this._scroller){
		var scrollVal = this._scroller.Value();
		scrollVal = (scrollVal < this._scroller.maxValue - 8) ? scrollVal += 8 : this._scroller.maxValue;

		this._scroller.Value(scrollVal);
		this._ScrollChanged(scrollVal);
		setTimeout('MN.TP.qmp.playlist.ScrollDown()',50);
	}
}

_pp.CurrentPage = function(num){
	if(num == null)
		return this._curPage;
	else{
		//function takes a number starting with 1
		if(num > 0 && num <= this._pagePositions.length){
			this._canvas.style.top = -this._pagePositions[num - 1] + 'px';
			if(this._scroller){
				this._scroller.Value(this._pagePositions[num - 1]);
			}
			this._curPage = num - 1;
			this.FireEvent('PageChanged', num, this._numOfPages);
		}
	}
}

//called when the scroller widget changes positions
_pp._ScrollChanged = function(value){
	this._scrollPane.Position(0,value);
	//find what page we are on
	var numBoxesAllowed = Math.floor(this._viewer.offsetHeight / this._canvas.firstChild.offsetHeight);
	var pageBump = this._canvas.firstChild.offsetHeight * numBoxesAllowed;
	var mid = value + (this._viewer.offsetHeight / 2);
	var bottom = value + this._viewer.offsetHeight;
	for(var i = this._pagePositions.length - 1; i >=0 ; i--){
		if(i == this._pagePositions.length - 1 && bottom >= this._pagePositions[i]){
			if(this._curPage != i){
				this._curPage = i;
				log('page changed: ' +  (this._curPage + 1) +  ' of ' + this._numOfPages);
			}
			return;
		}
		if(mid >= this._pagePositions[i] && mid < this._pagePositions[i] + pageBump){
			if(this._curPage != i){
				this._curPage = i;
				log('page changed: ' +  (this._curPage + 1) +  ' of ' + this._numOfPages);
			}
			return;
		}
	}
}

_pp.LoadContent = function(opt){
	log('Load content')
	//reset the playlist stuff
	if(this._epg){
		MN.Event.StopObserving(this._epg, 'urlLoaded', this._OnURLLoaded);
		this._epg = null;
	}
	log('reset dropdown')
	this._ResetDropdown();

	if(opt instanceof MN.EPG){
		log('playlist.LoadContent: loading EPG');
		if(this._dropdown){
			this._dropdown.style.visibility = 'visible';
			$('mn_dd_label').style.visibility = 'visible';
		}

		this._epg = opt;
		if(this._epg.IsDone())
			this._OnURLLoaded(this._epg.urlList, true, this._epg.name);
		else{
			if(this._epg.urlList.length >= 5){
				this._OnURLLoaded(this._epg.urlList, false, this._epg.name, true);
			}
			MN.Event.Observe(this._epg, 'urlLoaded', this._OnURLLoaded);
		}
	}
	else if(opt instanceof MN.QVT.QVT){
		log('playlist.LoadContent: loading qvt');
		if(this._dropdown){
			this._dropdown.style.visibility = 'hidden';
			$('mn_dd_label').style.visibility = 'hidden';
		}

		if(opt.IsLoading())
			MN.Event.Observe(opt, 'TimelineLoaded', this._LoadQVT);
		else
			this._LoadQVT(opt);
	}
	// else if(typeof opt == 'string' && opt)
}


_pp._ResetDropdown = function(){
	if(this._dropdown){
		log('have dropdown')
		var length = this._dropdown.options.length;
		for(var i = 0; i < length; i++){
			this._dropdown.removeChild(this._dropdown.options[0]);
		}

		log('creating dropdown')
		newOption = document.createElement('option');
		newOption.innerHTML = '<i>Cargando...&nbsp;</i>';
		//MN.SetInnerText(newOption,'<i>Cargando...&nbsp;</i>');
		newOption.setAttribute('value', 'loading');
		newOption.disabled = true;
		this._dropdown.appendChild(newOption);
		log('done loading dropdown')
	}
}

_pp._OnURLLoaded = function(urlList, isDone, name, override){
	if((this._dropdown) && (urlList.length % 3 == 0 || isDone || override)){
		log('playlist._OnURLLoaded: updating dropdown');

		//clear the "Loading..." option
		var numOfOptions = this._dropdown.options.length;
		var loadOpt;
		if(numOfOptions > 0){
			loadOpt = this._dropdown.options[numOfOptions - 1];
			if(loadOpt.getAttribute('value') == 'loading'){
				loadOpt = this._dropdown.removeChild(loadOpt);
				numOfOptions--;
			}
		}

		//update content dropdown
		var diff = urlList.length - numOfOptions;
		var url;
		for(var i = 0; i < diff; i++){
			url = urlList[numOfOptions + i];
			//don't show dates earlier than 2000 (ex 1/1/1970); _CreateContentOption will return -1 in that case
			if(this._CreateContentOption(url) != -1)
					this._dropdown.appendChild(this._CreateContentOption(url));
		}

		//add another "Loading..." option to let the user know that there is still more to load
				if(!isDone){
					//due to the _ResetDropdown function, loadOpt is guaranteed to exist, but still be safe
					if(loadOpt)
						this._dropdown.appendChild(loadOpt);
					else{
						var newOption = document.createElement('option');
						newOption.innerHTML = '<i>Cargando...&nbsp;</i>';
						newOption.setAttribute('value', 'loading');
						newOption.disabled = true;
						this._dropdown.appendChild(newOption);
					}
				}
	}
}

_pp._CreateContentOption = function(url){
	//because the qvt was cached when the EPG originally grabbed it, AcquireQVT
	//will immediately fetch the full qvt - no observation for TimelineLoaded is needed
	var qvt = MN.QVT.AcquireQVT(url);
	var date = qvt.StartDatetime();
	var text = '';
	var spanishDOW = ['Domingo', 'Lunes', 'Martes', 'Mi&#233;rcoles', 'Jueves', 'Viernes', 'S&#225;bado'];
		var spanishMonth = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
	qvt.meta.mn_content_type = 'live';
		var contentType = qvt.Metadata('mn_content_type') || 'vod';
	if(contentType == 'live'){
			//text = text = date.month + "/" + date.day + "/" + date.year;
			text = spanishDOW[date.dow] + ", " + date.day+ " " + spanishMonth[date.month-1] + ", " + date.year;
	}
	else if(contentType == 'vod')
		text = qvt.Metadata('title') || 'No Title';

	var newOption = document.createElement('option');
		newOption.setAttribute('value', url);
		newOption.innerHTML = text;
		//MN.SetInnerText(newOption,text);
		//if(qvt == MN.TP.qmp.CurrentQVT())
			//newOption.className = 'highlight';
		MN.QVT.ReleaseQVT(qvt);
		if(date.year < '2000')
				newOption = -1;
		return newOption;
}

_pp._SelectContent = function(){
	var option = this._dropdown.options[this._dropdown.selectedIndex];
	var url = option.value;
	if(url != 'loading'){
		qvt = MN.QVT.AcquireQVT(url);
		if(window.CustomDropdownSelected)
			CustomDropdownSelected();
		this._Populate(qvt);
		MN.QVT.ReleaseQVT(qvt);
	}
}

delete _pp;
